/*
 *	ME2 C++ SDK
 *	Copyright (c) 2010 _silencer
 *
 *	Permission is hereby granted, free of charge, to any person
 *	obtaining a copy of this software and associated documentation
 *	files (the "Software"), to deal in the Software without
 *	restriction, including without limitation the rights to use,
 *	copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the
 *	Software is furnished to do so, subject to the following
 *	conditions:
 *
 *	The above copyright notice and this permission notice shall be
 *	included in all copies or substantial portions of the Software.
 *
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *	OTHER DEALINGS IN THE SOFTWARE.
 */

#include "stdafx.h"
#include "unreal_sdk_generator.h"

namespace unreal
{
	void add_type_to_dependencies( uproperty::type_info& type, usdk_dependency_list& dependencies )
	{
		dependencies.insert( type.base );

		std::vector<uproperty::type_info>::iterator it( type.inner.begin() );

		for ( ; it != type.inner.end(); ++it )
			add_type_to_dependencies( *it, dependencies );
	}

	void usdk_collector::process( uint32 index )
	{
		if ( uobject::table_->is_valid( index ) )
		{
			uobject* object( (*uobject::table_)[index] );

			if ( object->is_valid() && object->is_a( uclass::static_get_class() ) )
			{
				/* Get class info or create new one if not found */
				usdk_class_info_ptr& obj_class_info( classes_map_[object->get_name()] );

				if ( !obj_class_info.get() )
				{
					obj_class_info.reset( new usdk_class_info() );
					classes_.push_back( obj_class_info );
				}

				/* If the class has been processed, no need to do it again (no dynamic changes) */
				if ( obj_class_info->processed )
					return;

				/* Name */
				obj_class_info->name = object->get_name();

				/* Package */
				uobject* obj_upper_outer( object->get_upper_outer() );

				if ( obj_upper_outer->is_valid() )
					obj_class_info->package = obj_upper_outer->get_name();
				else
					obj_class_info->package = "Unknown";

				/* Package list linkage */
				usdk_package_info_ptr& obj_package_info( packages_[obj_class_info->package] );

				if ( !obj_package_info.get() )
					obj_package_info.reset( new usdk_package_info() );

				usdk_class_info_ptr& obj_pacakge_class_info( obj_package_info->classes_map[obj_class_info->name] );

				if ( !obj_pacakge_class_info.get() )
				{
					obj_pacakge_class_info = obj_class_info;
					obj_package_info->classes.push_back( obj_class_info );
				}

				/* Extends from? */
				ufield* super( reinterpret_cast<ufield*>(object)->get_super_field() );
				if ( super->is_valid() )
					obj_class_info->super = super->get_name();
				else
					obj_class_info->super = "Object";

				/* Add base objects to dependency map */
				for ( ; super->is_valid(); super = super->get_super_field() )
						obj_class_info->dependencies.insert( super->get_name() );

				uclass* obj_class( reinterpret_cast<uclass*>( object ) );

				/* Process all children fields */
				for ( ufield* obj_field( obj_class->get_children() ); obj_field->is_valid(); obj_field = obj_field->get_next() )
				{
					if ( !obj_field->is_valid() )
						continue;

					uclass* obj_field_class( obj_field->get_class() );

					if ( !obj_field_class->is_valid() )
						continue;

					/* Variable */
					if ( ( obj_field_class->get_class_flags() & uclass_isa_uproperty ) != 0 )
					{
						/* Process variable information and add to list */
						uproperty* variable( reinterpret_cast<uproperty*>(obj_field) );
						usdk_variable_info_ptr variable_info( new usdk_variable_info( variable ) );

						obj_class_info->variables.push_back( variable_info );

						/* Add variable type to dependency map */
						add_type_to_dependencies( variable_info->type, obj_class_info->dependencies );

						continue;
					}

					/* Function */
					if ( ( obj_field_class->get_class_flags() & uclass_isa_ufunction ) != 0 )
					{
						/* Process function */
						ufunction* function( reinterpret_cast<ufunction*>(obj_field) );
						usdk_function_info_ptr function_info( new usdk_function_info() );

						function_info->name = function->get_name();
						function_info->full_name = function->get_full_name();

						/* Parameter definitions are children of the function */
						for ( ufield* func_field( function->get_children() ); func_field->is_valid(); func_field = func_field->get_next() )
						{
							if ( !func_field->is_valid() )
								continue;

							uclass* func_field_class( func_field->get_class() );

							if ( !func_field_class->is_valid() )
								continue;

							if ( ( func_field_class->get_class_flags() & uclass_isa_uproperty ) == 0 )
								continue;

							uproperty* variable( reinterpret_cast<uproperty*>(func_field) );
							usdk_variable_info_ptr variable_info( new usdk_variable_info( variable ) );

							if ( variable_info->is_return_value )
								function_info->return_value = variable_info;

							function_info->variables.push_back( variable_info );

							/* Add variable type to dependency map */
							add_type_to_dependencies( variable_info->type, obj_class_info->dependencies );
						}

						obj_class_info->functions.push_back( function_info );

						continue;
					}

					/* Structure */
					if ( obj_field->is_a( ustruct::static_get_class() ) )
					{
						/* Process structure (currently can also be a state! so can include functions in the unknowns list */
						ustruct* structure( reinterpret_cast<ustruct*>(obj_field) );
						usdk_structure_info_ptr structure_info( new usdk_structure_info() );

						structure_info->name = structure->get_name();

						for ( ufield* struct_field( structure->get_children() ); struct_field->is_valid(); struct_field = struct_field->get_next() )
						{
							if ( !struct_field->is_valid() )
								continue;

							uclass* struct_field_class( struct_field->get_class() );

							if ( !struct_field_class->is_valid() )
								continue;

							if ( ( struct_field_class->get_class_flags() & uclass_isa_uproperty ) == 0 )
							{
								structure_info->unknowns.push_back( struct_field->get_name() );

								continue;
							}

							uproperty* variable( reinterpret_cast<uproperty*>(struct_field) );
							usdk_variable_info_ptr variable_info( new usdk_variable_info( variable ) );

							structure_info->variables.push_back( variable_info );

							/* Add variable type to dependency maps */
							add_type_to_dependencies( variable_info->type, structure_info->dependencies );
							add_type_to_dependencies( variable_info->type, obj_class_info->dependencies );
						}

						/* Some structures also define a new state for the object (overrides behavior) */
						if ( obj_field->is_a( ustate::static_get_class() ) )
							structure_info->is_state = true;

						obj_class_info->structures.push_back( structure_info );

						continue;
					}

					/* Enumeration */
					if ( obj_field->is_a( uenum::static_get_class() ) )
					{
						/* Process enumeration (first entry is name, second is the override value) */
						uenum* enumeration( reinterpret_cast<uenum*>(obj_field) );
						usdk_enumeration_info_ptr enum_info( new usdk_enumeration_info() );

						enum_info->name = enumeration->get_name();

						uarray<uname>& names( enumeration->get_names() );
						
						uint32 unknowns( 0 );
						usdk_constant_info_ptr item( new usdk_constant_info() );

						for ( uint32 i( 0 ); i < names.size(); ++i )
						{
							if ( names[i].is_valid() )
							{
								if ( ( i % 2 ) == 0 )
								{
									item->name = names[i].get_str();
								}
								else
								{
									if ( names[i].is_none() )
										item->value = "";
									else
										item->value = boost::lexical_cast<std::string>(names[i].get_index());

									enum_info->values.push_back( item );

									item.reset( new usdk_constant_info() );
								}
							}
							else
							{
								std::string str( "unknown_" );
								str += boost::lexical_cast<std::string>( unknowns++ );
								item->name = str;
								item->value = "";
								enum_info->values.push_back( item );
							}
						}

						/* If last item doesn't have value included make sure it is added */
						if ( ( names.size() > 0 ) && ( ( ( names.size() - 1 ) % 2 ) == 0 ) )
						{
							item->value = "";
							enum_info->values.push_back( item );
						}

						obj_class_info->enumerations.push_back( enum_info );

						continue;
					}

					/* Constant */
					if ( obj_field->is_a( uconst::static_get_class() ) )
					{
						/* Process constant (string is wide, so need to convert to simple c string) */
						/* This unreal engine build is weird, some core stuff is char* other wchar_t*... */
						uconst* constant( reinterpret_cast<uconst*>(obj_field) );
						usdk_constant_info_ptr const_info( new usdk_constant_info() );

						const_info->name = constant->get_name();
						//const_info->value = constant->get_value().get_str();
						//std::copy( constant->get_value().get_str(), constant->get_value().get_str() + constant->get_value().size(), std::back_inserter( const_info->value ) );
						const_info->value = constant->value_to_ascii_str();

						obj_class_info->constants.push_back( const_info );

						continue;
					}

					/* Unknown */
					std::string unknown_name( obj_field->get_name() );
					obj_class_info->unknowns.push_back( unknown_name );
				}

				obj_class_info->processed = true;
			}
		}
	}

	void usdk_collector::sort()
	{
		topological_sorter<usdk_class_info>( classes_ ).sort();

		usdk_package_list_iterator package_it( packages_.begin() );

		for ( ; package_it != packages_.end(); ++package_it )
		{
			usdk_package_info_ptr package_info( package_it->second );

			if ( package_info.get() )
				topological_sorter<usdk_class_info>( package_info->classes ).sort();
		}
	}

	void native_output_variable_list( std::ostream& output, usdk_variable_list& variables, std::string tab = "", bool hide_special = true )
	{
		usdk_variable_list_iterator var_it( variables.begin() );

		for ( ; var_it != variables.end(); ++var_it )
		{
			usdk_variable_info_ptr var_info( *var_it );

			if ( var_info.get() )
			{
				if ( var_info->is_return_value && hide_special )
					continue;

				if ( var_info->type.base == "Bool" )
					output << tab << "Bool " << var_info->name << ": 1; //offset = " << var_info->offset << ", size = " << var_info->element_size << std::endl;
				else
					if ( var_info->element_count > 1 )
						output << tab << var_info->type.get_str( "*" ) << " " << var_info->name << "[" << var_info->element_count << "]; //offset = " << var_info->offset << ", size = " << var_info->element_size << std::endl;
					else
						output << tab << var_info->type.get_str( "*" ) << " " << var_info->name << "; //offset = " << var_info->offset << ", size = " << var_info->element_size << std::endl;
			}
		}
	}

	void native_output_function_variable_list( std::ostream& output, usdk_variable_list& variables, bool hide_special = true )
	{
		if ( variables.empty() )
			return;

		usdk_variable_list_iterator var_it( variables.begin() );

		bool has_return_value( false );

		for ( ; var_it != variables.end(); ++var_it )
		{
			usdk_variable_info_ptr var_info( *var_it );

			if ( var_info.get() )
			{
				if ( var_info->is_return_value && hide_special )
				{
					has_return_value = true;
					continue;
				}

				if ( var_it == variables.begin() )
					output << " ";
				else
					output << ", ";
				
				output << var_info->type.get_str( "*" ) << " " << var_info->name;

				usdk_variable_list_iterator end_check_it( var_it + 1 );
			}
		}

		if ( has_return_value )
		{
			if ( variables.size() > 1 )
				output << " ";
		}
		else
		{
			output << " ";
		}
	}

	void unative_sdk_generator::build_global_header( std::ostream& output )
	{
		output << "/*" << std::endl;
		output << " * Auto generated C++ header for Mass Effect 2." << std::endl;
		output << " *	by _silencer." << std::endl;
		output << " */" << std::endl;
		output << std::endl;
		output << "#ifndef UNREAL_SDK_GAME_GLOBAL_H" << std::endl;
		output << "#define UNREAL_SDK_GAME_GLOBAL_H" << std::endl;
		output << std::endl;
		output << "#include \"unreal_sdk.h\"" << std::endl;
		output << std::endl;
		output << "namespace game" << std::endl;
		output << "{" << std::endl;
		output << "	using namespace unreal;" << std::endl;
		output << std::endl;
		output << "	#define Byte int8" << std::endl;
		output << "	#define Int int32" << std::endl;
		output << "	#define Bool bool" << std::endl;
		output << "	#define Pointer void*" << std::endl;
		output << "	#define Name uname" << std::endl;
		output << "	#define Array uarray" << std::endl;
		output << "	#define Map umap" << std::endl;
		output << "	#define String ustring" << std::endl;
		output << "	#define Object uobject" << std::endl;
		output << "	#define TextBuffer utextbuffer" << std::endl;
		output << "	#define Component ucomponent" << std::endl;
		output << "	#define Field ufield" << std::endl;
		output << "	#define Enum uenum" << std::endl;
		output << "	#define Const uconst" << std::endl;
		output << "	#define Property uproperty" << std::endl;
		output << "	#define ByteProperty ubyteproperty" << std::endl;
		output << "	#define IntProperty uintproperty" << std::endl;
		output << "	#define BoolProperty uboolproperty" << std::endl;
		output << "	#define FloatProperty ufloatproperty" << std::endl;
		output << "	#define ObjectProperty uobjectproperty" << std::endl;
		output << "	#define ClassProperty uclassproperty" << std::endl;
		output << "	#define NameProperty unameproperty" << std::endl;
		output << "	#define ArrayProperty uarrayproperty" << std::endl;
		output << "	#define MapProperty umapproperty" << std::endl;
		output << "	#define StrProperty ustrproperty" << std::endl;
		output << "	#define StructProperty ustructproperty" << std::endl;
		output << "	#define ComponentProperty ucomponentproperty" << std::endl;
		output << "	#define Struct ustruct" << std::endl;
		output << "	#define Function ufunction" << std::endl;
		output << "	#define State ustate" << std::endl;
		output << "	#define Class uclass" << std::endl;
		output << std::endl;

		usdk_class_list& classes( collector_.get_classes() );
		usdk_class_list_iterator class_it( classes.begin() );

		for ( ; class_it != classes.end(); ++class_it )
		{
			usdk_class_info_ptr class_info( *class_it );

			if ( !class_info.get() )
				continue;

			output << "	class " << class_info->name << ";" << std::endl;
		}

		output << "}" << std::endl;
		output << std::endl;
		output << "#endif" << std::endl;
		//output << std::endl;
	}

	void unative_sdk_generator::build_header( std::ostream& output, std::string package )
	{
		output << "/*" << std::endl;
		output << " * Auto generated C++ header for Mass Effect 2." << std::endl;
		output << " *	by _silencer." << std::endl;
		output << " */" << std::endl;
		output << std::endl;

		if ( package != "" )
		{
			output << "#ifndef UNREAL_SDK_GAME_" << package << "_H" << std::endl;
			output << "#define UNREAL_SDK_GAME_" << package << "_H" << std::endl;
		}
		else
		{
			output << "#ifndef UNREAL_SDK_GAME_H" << std::endl;
			output << "#define UNREAL_SDK_GAME_H" << std::endl;
		}

		output << std::endl;
		output << "#include \"unreal_game_global.h\"" << std::endl;
		output << std::endl;
		output << "namespace game" << std::endl;
		output << "{" << std::endl;
		output << "	using namespace unreal;" << std::endl;
		output << std::endl;

		usdk_class_list* classes( &collector_.get_classes() );

		if ( package != "" )
		{
			usdk_package_info_ptr package_info( collector_.get_packages()[package] );

			if ( package_info.get() )
				classes = &package_info->classes;
		}

		usdk_class_list_iterator class_it( classes->begin() );
		bool not_first_class( false );

		for ( ; class_it != classes->end(); ++class_it )
		{
			usdk_class_info_ptr class_info( *class_it );

			if ( !class_info.get() )
				continue;

			if ( !class_info->processed )
				continue;

			//if ( class_info->name == "Object" )
			//	continue;

			/* Not first class bool (could also check iterator == begin()... ) */
			if ( not_first_class )
				output << std::endl;
			else
				not_first_class = true;

			/*
			 *	Constants, enumeration, data structures are defined out of class scope!
			 */

			/* Constant */
			usdk_constant_list& constants( class_info->constants );
			usdk_constant_list_iterator const_it( constants.begin() );

			for ( ; const_it != constants.end(); ++const_it )
			{
				usdk_constant_info_ptr const_info( *const_it );

				if ( const_info.get() )
					output << "	#define " << const_info->name << " " << const_info->value << std::endl;
			}

			if ( constants.size() > 0 )
				output << std::endl;

			/* Enumeration */
			usdk_enumeration_list& enumerations( class_info->enumerations );
			usdk_enumeration_list_iterator enum_it( enumerations.begin() );

			for ( ; enum_it != enumerations.end(); ++enum_it )
			{
				usdk_enumeration_info_ptr enum_info( *enum_it );

				if ( enum_info.get() )
				{
					output << "	enum " << enum_info->name << std::endl;
					output << "	{" << std::endl;

					usdk_constant_list& values( enum_info->values );
					usdk_constant_list_iterator val_it( values.begin() );

					for ( ; val_it != values.end(); ++val_it )
					{
						if ( (*val_it)->value == "" )
							output << "		" << (*val_it)->name << "," << std::endl;
						else
							output << "		" << (*val_it)->name << " = " << (*val_it)->value << "," << std::endl;
					}

					output << "	};" << std::endl;

					if ( ( enum_it + 1 ) != enumerations.end() )
						output << std::endl;
				}
			}

			if ( enumerations.size() > 0 )
				output << std::endl;

			/* Structure (data) */
			usdk_structure_list& structures( class_info->structures );

			/* Sort structures first to make sure dependencies are ok */
			topological_sorter<usdk_structure_info>( structures ).sort();

			usdk_structure_list_iterator struct_it( structures.begin() );

			for ( ; struct_it != structures.end(); ++struct_it )
			{
				usdk_structure_info_ptr struct_info( *struct_it );

				/* Only data structures */
				if ( struct_info.get() && !struct_info->is_state )
				{
					output << "	struct " << struct_info->name << std::endl;
					output << "	{" << std::endl;

					native_output_variable_list( output, struct_info->variables, "		" );

					usdk_unknown_list& unknowns( struct_info->unknowns );
					usdk_unknown_list_iterator unk_it( unknowns.begin() );

					if ( unknowns.size() > 0 )
					{
						if ( struct_info->variables.size() > 0)
							output << std::endl;

						output << "		/*" << std::endl;

						for ( ; unk_it != unknowns.end(); ++unk_it )
						{
							std::string& unknown_info( *unk_it );

							output << "		" << unknown_info << std::endl;
						}

						output << "		*/" << std::endl;
					}

					output << "	};" << std::endl;

					if ( ( struct_it + 1 ) != structures.end() )
						output << std::endl;
				}
			}

			if ( structures.size() > 0 )
				output << std::endl;

			output << "	class " << class_info->name << ": public " << class_info->super << std::endl;
			output << "	{" << std::endl;
			output << "		DECLARE_PACKAGE_CLASS( " << class_info->name << ", " << class_info->super << ", " << class_info->package << " )" << std::endl;
			output << std::endl;
			output << "	public:" << std::endl;

			/* Structure (state) */
			struct_it = structures.begin();

			for ( ; struct_it != structures.end(); ++struct_it )
			{
				usdk_structure_info_ptr struct_info( *struct_it );

				/* Only state structures */
				if ( struct_info.get() && struct_info->is_state )
				{
					output << "		struct " << struct_info->name << std::endl;
					output << "		{" << std::endl;

					native_output_variable_list( output, struct_info->variables, "			" );

					usdk_unknown_list& unknowns( struct_info->unknowns );
					usdk_unknown_list_iterator unk_it( unknowns.begin() );

					if ( unknowns.size() > 0 )
					{
						if ( struct_info->variables.size() > 0)
							output << std::endl;

						output << "			/*" << std::endl;

						for ( ; unk_it != unknowns.end(); ++unk_it )
						{
							std::string& unknown_info( *unk_it );

							output << "			" << unknown_info << std::endl;
						}

						output << "			*/" << std::endl;
					}

					output << "		};" << std::endl;

					if ( ( struct_it + 1 ) != structures.end() )
						output << std::endl;
				}
			}

			/* Variable */
			if ( class_info->variables.size() > 0 )
				output << std::endl;

			native_output_variable_list( output, class_info->variables, "		" );

			/* Function */
			usdk_function_list& functions( class_info->functions );
			usdk_function_list_iterator func_it( functions.begin() );

			if ( functions.size() > 0 )
				output << std::endl;

			for ( ; func_it != functions.end(); ++func_it )
			{
				usdk_function_info_ptr func_info( *func_it );

				if ( func_info.get() )
				{
					usdk_variable_info_ptr return_value( func_info->return_value );

					if ( return_value.get() )
						output << "		" << return_value->type.get_str( "*" );
					else
						output << "		void";

					output << " " << func_info->name << "(";

					native_output_function_variable_list( output, func_info->variables );

					output << ");" << std::endl;
				}
			}

			/* Unknown */
			usdk_unknown_list& unknowns( class_info->unknowns );
			usdk_unknown_list_iterator unk_it( unknowns.begin() );

			if ( unknowns.size() > 0 )
			{	
				output << std::endl;
				output << "/*" << std::endl;

				for ( ; unk_it != unknowns.end(); ++unk_it )
				{
					std::string& unknown_info( *unk_it );

					output << unknown_info << std::endl;
				}

				output << "*/" << std::endl;
			}

			output << "	};" << std::endl;
		}

		output << "}" << std::endl;
		output << std::endl;
		output << "#endif" << std::endl;
		//output << std::endl;
	}

	void unative_sdk_generator::build_implementation( std::ostream& output, std::string package )
	{
		output << "/*" << std::endl;
		output << " * Auto generated C++ implementation for Mass Effect 2." << std::endl;
		output << " *	by _silencer." << std::endl;
		output << " */" << std::endl;
		output << std::endl;
		output << "#include \"stdafx.h\"" << std::endl;
		output << "#include \"unreal_game.h\"" << std::endl;
		output << std::endl;
		output << "namespace game" << std::endl;
		output << "{" << std::endl;

		usdk_class_list* classes( &collector_.get_classes() );

		if ( package != "" )
		{
			usdk_package_info_ptr package_info( collector_.get_packages()[package] );

			if ( package_info.get() )
				classes = &package_info->classes;
		}

		usdk_class_list_iterator class_it( classes->begin() );

		for ( ; class_it != classes->end(); ++class_it )
		{
			usdk_class_info_ptr class_info( *class_it );

			if ( !class_info.get() )
				continue;

			output << "	IMPLEMENT_PACKAGE_CLASS( " << class_info->name << ", " << class_info->super << ", " << class_info->package << " )" << std::endl;
		}
		output << std::endl;

		class_it = classes->begin();
		for ( ; class_it != classes->end(); ++class_it )
		{
			usdk_class_info_ptr class_info( *class_it );

			if ( !class_info.get() )
				continue;

			if ( !class_info->processed )
				continue;

			usdk_function_list& functions( class_info->functions );
			usdk_function_list_iterator func_it( functions.begin() );

			for ( ; func_it != functions.end(); ++func_it )
			{
				usdk_function_info_ptr func_info( *func_it );

				if ( func_info.get() )
				{
					output << std::endl;

					usdk_variable_info_ptr return_value( func_info->return_value );

					if ( return_value.get() )
						output << "	" << return_value->type.get_str( "*" );
					else
						output << "	void";

					output << " " << class_info->name << "::" << func_info->name << "(";

					usdk_variable_list& variables( func_info->variables );

					native_output_function_variable_list( output, variables );

					output << ")" << std::endl;
					output << "	{" << std::endl;

					output << "		static ufunction* function = 0;" << std::endl;
					output << std::endl;
					output << "		if ( !function )" << std::endl;
					output << "			function = find_global_object<ufunction>( \"" << func_info->full_name << "\" );" << std::endl;
					output << std::endl;

					if ( ( variables.size() > 0 ) || return_value.get() )
					{
						output << "		struct " << func_info->name << "Params" << std::endl;
						output << "		{" << std::endl;

						native_output_variable_list( output, variables, "			", false );

						output << "		} params;" << std::endl;
						output << std::endl;

						usdk_variable_list_iterator var_it( variables.begin() );

						for ( ; var_it != variables.end(); ++var_it )
						{
							usdk_variable_info_ptr var_info( *var_it );

							if ( var_info.get() && !var_info->is_return_value )
								output << "		params." << var_info->name << " = " << var_info->name << ";" << std::endl;
						}

						output << std::endl;
						output << "		this->call_function( function, &params, 0 );" << std::endl;

						if ( return_value.get() )
						{
							output << std::endl;
							output << "		return params.ReturnValue;" << std::endl;
						}
					}
					else
					{
						output << "		this->call_function( function, 0, 0 );" << std::endl;
					}

					output << "	}" << std::endl;
				}
			}
		}

		output << "}" << std::endl;
		//output << std::endl;
	}
}
